using System;
using System.Collections.Generic;
using System.Linq;
using GameFramework.Fsm;
using UnityEngine;
using UnityGameFramework.Runtime;

namespace LS.Fsm
{
    public class SequenceFsmContainer<T> where T : class
    {
        public event Action OnSequenceFinished;

        private T m_Owner;
        private IFsm<SequenceFsmContainer<T>> m_Fsm;
        private readonly List<FsmState<SequenceFsmContainer<T>>> m_States;
        private readonly List<Type> m_StateTypes;
        
        public T Owner => m_Owner;
        public IFsm<SequenceFsmContainer<T>> Fsm => m_Fsm;
        public int Count { get { return m_States.Count; } }
        public bool IsRunning { get { return m_Fsm?.IsRunning ?? false; } }
        
        public SequenceFsmContainer(T owner)
        {
            this.m_Owner = owner;
            m_StateTypes = new List<Type>();
            m_States = new List<FsmState<SequenceFsmContainer<T>>>();
        }
        
        public SequenceFsmContainer(T owner, FsmState<SequenceFsmContainer<T>>[] states = null)
        {
            this.m_Owner = owner;
            m_StateTypes = new List<Type>();
            this.m_States = new List<FsmState<SequenceFsmContainer<T>>>();
            m_StateTypes.AddRange(states.Select(s=>s.GetType()));
            if (states != null && states.Length > 0)
            {
                m_States.AddRange(states);
            }
        }

        public void Start()
        {
            if (m_Fsm == null)
            {
                m_Fsm = LSEntry.Fsm.CreateFsm(this, m_States.ToArray());
                m_Fsm.Start(GetFirstStateType());
            }
            else
            {
                Log.Warning("Fsm container is already running");
            }
        }

        public void Stop()
        {
            if (m_Fsm != null)
            {
                LSEntry.Fsm.DestroyFsm(m_Fsm);
                m_Fsm = null;
            }
        }

        public FsmState<SequenceFsmContainer<T>> GetFirstState()
        {
            return m_States[0];
        }
        
        public Type GetFirstStateType()
        {
            return m_StateTypes[0];
        }
        
        public int IndexOf(FsmState<SequenceFsmContainer<T>> state)
        {
            return m_States.IndexOf(state);
        }

        public FsmState<SequenceFsmContainer<T>> GetState(int index)
        {
            if (index < 0 || index >= m_States.Count)
                return null;

            return m_States[index];
        }
        
        public Type GetStateType(int index)
        {
            if (index < 0 || index >= m_States.Count)
                return null;

            return m_StateTypes[index];
        }
        
        public void Add(FsmState<SequenceFsmContainer<T>> state)
        {
            m_States.Add(state);
            m_StateTypes.Add(state.GetType());
        }

        public void Remove(FsmState<SequenceFsmContainer<T>> state)
        {
            m_States.Remove(state);
            m_StateTypes.Remove(state.GetType());
        }
        
        public void Clear()
        {
            m_States.Clear();
            m_StateTypes.Clear();
        }

        internal void OnFsmFinished()
        {
            Stop();
            OnSequenceFinished?.Invoke();
        }
    }
}
